package com.syf.core.service.run.chain.impl;

import com.syf.core.exception.ExceptionUtils;
import com.syf.core.service.SyService;
import com.syf.core.service.SyServiceDefinition;
import com.syf.core.service.context.ServiceContext;
import com.syf.core.service.context.ServiceRequest;
import com.syf.core.service.context.ServiceResponse;
import com.syf.core.service.enums.ResponseFormatEnums;
import com.syf.core.service.run.chain.ServiceExecutionChain;
import com.syf.core.service.run.chain.ServicePrePostHandle;
import com.syf.core.utils.BeanValidatorUtils;
import lombok.extern.slf4j.Slf4j;

import javax.validation.ConstraintViolation;
import java.util.List;
import java.util.Set;

/**
 * service执行前后处理链
 */
@Slf4j
public class DefaultServicePrePostChain implements ServiceExecutionChain {

    private final ServicePrePostHandleChainNode headNodeWrapper;

    private final ServicePrePostHandleChainNode tailNodeWrapper;

    private final SyService service;

    public DefaultServicePrePostChain(SyService service, List<ServicePrePostHandle> handleList) {
        this.headNodeWrapper = new ServicePrePostHandleChainNode(new HeadNode());
        this.tailNodeWrapper = new ServicePrePostHandleChainNode(new TailNode());
        this.service = service;
        headNodeWrapper.setNext(tailNodeWrapper);
        tailNodeWrapper.setPre(headNodeWrapper);

        handleList.forEach(this::insertNode);
    }

    /**
     * 按tail节点顺序插入节点
     */
    public void insertNode(ServicePrePostHandle prePostHandle) {
        ServicePrePostHandleChainNode handleWrapper = new ServicePrePostHandleChainNode(prePostHandle);
        handleWrapper.setPre(tailNodeWrapper.getPre());
        tailNodeWrapper.getPre().setNext(handleWrapper);

        tailNodeWrapper.setPre(handleWrapper);
        handleWrapper.setNext(tailNodeWrapper);
    }

    /**
     * 执行处理链
     */
    @Override
    public void processed(ServiceContext context) {
        headNodeWrapper.processPreHandle(context);
    }

    /**
     * 执行service
     */
    public void runService(ServiceContext context) {
        service.execute(context);
        log.debug("service execute end");
        tailNodeWrapper.processPostHandle(context);
    }

    private static class HeadNode implements ServicePrePostHandle {

        @Override
        public boolean support(SyServiceDefinition serviceDefinition) {
            return true;
        }

        @Override
        public int getOrder() {
            return Integer.MIN_VALUE;
        }

        @Override
        public boolean preHandle(ServiceContext context) {
            log.debug("Pre-service processing begin");
            log.debug("校验输入参数的合法性");

            Set<ConstraintViolation<ServiceRequest>> validateResult = BeanValidatorUtils.validateBean(context.getRequest(), ServiceRequest.class);
            if (validateResult != null && !validateResult.isEmpty()) {
                context.getResponse().setError(ResponseFormatEnums.REQUEST_PARAM_IS_ILLEGAL, BeanValidatorUtils.buildValidateMessage(validateResult, ServiceRequest.class));
                return false;
            }

            return true;
        }

        @Override
        public void postHandle(ServiceContext context) {
            if (log.isDebugEnabled()) {
                log.debug("校验响应参数的合法性");
            }

            // service response非空检查
            if (context.getResponse() == null) {
                throw new RuntimeException("必须设置service response对象");
            }

            // 交易成功，则对返回的业务响应体数据进行校验
            if (context.getResponse().isSuccess()) {
                Set<ConstraintViolation<ServiceResponse>> validateResult = BeanValidatorUtils.validateBean(context.getResponse(), ServiceResponse.class);
                if (!(validateResult == null || validateResult.isEmpty())) {
                    String validReason = BeanValidatorUtils.buildValidateMessage(validateResult, ServiceResponse.class);
                    log.error("响应数据校验非法，具体原因：{}", validReason);
                    context.getResponse().setError(ResponseFormatEnums.RESPONSE_PARAM_IS_ILLEGAL, validReason);
                }
            }
        }

    }

    private class TailNode implements ServicePrePostHandle {
        @Override
        public boolean support(SyServiceDefinition serviceDefinition) {
            return true;
        }

        @Override
        public int getOrder() {
            return Integer.MAX_VALUE;
        }

        @Override
        public boolean preHandle(ServiceContext context) {
            log.debug("Pre-service processing end");
            log.debug("service execute start");
            // 执行service
            try {
                runService(context);
                log.debug("service execute end");
            } catch (Exception e) {
                context.getResponse().setError("99001", "执行service出现异常:" + e);
                log.error("执行交易:[{}]出现异常，异常堆栈信息如下:\n{}", context.getRequest().getHead().getServiceDefinition().getServiceCode(), ExceptionUtils.getExceptionStackInfo(e));
            }

            return true;
        }

        @Override
        public void postHandle(ServiceContext context) {
            // 执行后处理
            log.debug("Post-service processing begin");
        }
    }
}
